package com.weilx959.spt.plugin.e2sp.utils.sql.parser;

import com.weilx959.spt.plugin.e2sp.constant.ExcelToSqlConstants;
import com.weilx959.spt.plugin.e2sp.exception.ExcelException;
import com.weilx959.spt.plugin.e2sp.model.statement.InsertStatement;
import com.weilx959.spt.plugin.e2sp.model.statement.Statement;
import com.weilx959.spt.plugin.e2sp.utils.ResourceBundleUtil;
import com.weilx959.spt.plugin.e2sp.utils.sql.SqlUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.Values;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import net.sf.jsqlparser.util.deparser.SelectDeParser;
import net.sf.jsqlparser.util.deparser.StatementDeParser;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;

/**
 * INSERT SQL解析器
 *
 * @author weilx
 * @since 2024-05-02
 */
@Slf4j
public class InsertSQLParser implements SQLParser {
    private static final ResourceBundle bundle = ResourceBundleUtil.get();

    @Override
    public String parse(Statement statement) {
        InsertStatement insertStatement = SqlUtil.cast(statement, InsertStatement.class);
        // table
        Insert insert = new Insert();
        insert.setTable(new Table(insertStatement.getSchema(), insertStatement.getTableName()));

        // columns
        List<Column> columnList = insertStatement.getColumns().stream().map(Column::new).toList();
        insert.addColumns(columnList);

        // values
        Values values = new Values();
        List<Expression> valueExpressionList = insertStatement.getValues().stream().map(SqlUtil::getValueExpression).toList();
        values.addExpressions(valueExpressionList);
        insertStatement.setInsert(insert);
        insertStatement.setValue(values);
        StringBuilder sb = new StringBuilder();

        try {
            ExpressionDeParser expressionDeParser = Optional.ofNullable(insertStatement.getDialect())
                    .orElse(ExcelToSqlConstants.DEFAULT_DIALECT)
                    .getDeparserClass()
                    .getDeclaredConstructor()
                    .newInstance();
            StatementDeParser statementDeParser = new StatementDeParser(expressionDeParser, new SelectDeParser(), sb);
            insert.accept(statementDeParser);
            sb.append(ExcelToSqlConstants.NEW_LINE);
            values.accept(statementDeParser);
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            throw new ExcelException(bundle.getString("e2s.de-parse.insert.error"), e);
        }
        sb.append(ExcelToSqlConstants.SEMICOLON);
        return sb.toString();
    }
}
